<?php

declare (strict_types = 1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
 */
namespace App\Service\Auth;

use App\Constants\ErrorCode;
use App\Dao\AuthAdminLogDao;
use App\Dao\AuthEmployeeDao;
use App\Dao\AuthOrganizationDao;
use App\Dao\AuthRoleComponentDao;
use App\Dao\CompanyModuleDao;
use App\Dao\ComponentDao;
use App\Dao\DepartComponentDao;
use App\Dao\MenuComponentDao;
use App\Dao\MenuDao;
use App\Dao\ModuleDao;
use App\Exception\BusinessException;
use App\Model\Component;
use App\Utils\ApiUtils;
use App\Utils\FunctionUtil;
use App\Utils\Redis;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Codec\Json;

class ModuleService
{

    /**
     * @Inject
     * @var Redis
     */
    protected $redis;

    /**
     * @Inject
     * @var ModuleDao
     */
    protected $mdao;

    /**
     * @Inject
     * @var ComponentDao
     */
    protected $cdao;

    /**
     * @Inject
     * @var MenuDao
     */
    protected $menudao;

    /**
     * @Inject
     * @var MenuComponentDao
     */
    protected $mcdao;

    /**
     * @Inject
     * @var DepartComponentDao
     */
    protected $ddao;

    public function addComponent($params)
    {
        // $where = [];
        // $where[] = ['module_id', '=', $params['module_id']];
        // $where[] = ['component_name', '=', $params['component_name']];
        // $info = $this->cdao->searchFirst($where);
        // if (!empty($info)) {
        //     throw new BusinessException(ErrorCode::ERR_BUESSUS, '该功能名字已存在');
        // }
        $map = [];
        $map['url'] = $params['url'] ?? '';
        $map['module_id'] = $params['module_id'];
        $map['content'] = $params['content'] ?? '';
        $map['icon'] = $params['icon'] ?? '';
        $map['component_name'] = $params['component_name'];
        $map['pid'] = $params['pid'];
        $map['is_web'] = $params['is_web'];
        $map['sort'] = $params['sort'] ?? 0;
        $map['identity'] = $params['identity'];
        $id = $this->cdao->add($map);
        make(AuthAdminLogDao::class)->addLog('添加了模块组件' . json_encode($params));
        return ApiUtils::send(ErrorCode::SUCCESS, '添加成功', $id);

    }

    public function componentCate($params)
    {
        if (isset($params['module_id']) && !empty($params['module_id'])) {
            $data = $this->mdao->searchAll([['id', '=', $params['module_id']]], [], ['module_name', 'id']);
        } else {
            $data = $this->mdao->searchAll([], [], ['module_name', 'id']);
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $data);

    }

    public function editComponent($params)
    {
        // $where = [];
        // $where[] = ['module_id', '=', $params['module_id']];
        // $where[] = ['component_name', '=', $params['component_name']];
        // $info = $this->cdao->searchFirst($where);
        // if (!empty($info) && $info['id'] != $params['id']) {
        //     throw new BusinessException(ErrorCode::ERR_BUESSUS, '该功能名字已存在');
        // }
        $map = [];
        $map['url'] = $params['url'] ?? '';
        $map['module_id'] = $params['module_id'];
        $map['content'] = $params['content'] ?? '';
        $map['icon'] = $params['icon'] ?? '';
        $map['component_name'] = $params['component_name'];
        $map['update_time'] = \time();
        if (isset($params['pid']) && !empty($params['pid'])) {
            $map['pid'] = $params['pid'];
        }
        $map['is_web'] = $params['is_web'];
        $map['sort'] = $params['sort'] ?? 0;
        $map['identity'] = $params['identity'];
        $where1 = [];
        $where1[] = ['id', '=', $params['id']];
        $id = $this->cdao->update($where1, $map);
        make(AuthAdminLogDao::class)->addLog('修改了模块组件' . json_encode($params));
        return ApiUtils::send(ErrorCode::SUCCESS, '修改成功', $id);

    }

    public function delComponent($params)
    {
        Db::beginTransaction();
        try {
            //找出自己和下级
            $is = [];
            $is[] = ['pid', '=', $params['id']];
            $componentIds = $this->getSon([$params['id']]);
            $componentIds[] = $params['id'];
            //$del = [];
            //$del[] = ['id', '=', $params['id']];
            $count = $this->cdao->delete([], $componentIds);
            //删除栏目功能
            //$del1 = [];
            //$del1[] = ['component_id', '=', $params['id']];
            $this->mcdao->delete([], $componentIds);
            //删除角色关联
            make(AuthRoleComponentDao::class)->deleteByWhereAndInTrait([], 'component_id', $componentIds);
            //删除部门功能并清除缓存
            //$where = [];
            //$where[] = ['component_id', '=', $params['id']];
            //$ori_ids = $this->ddao->searchOriId($where);
            $where5 = [];
            $where5[] = ['company_id', '=', $params['login_usr']['company_id']];
            $ori_ids = make(AuthOrganizationDao::class)->getByWhereTrait($where5, ['id'])->toArray();
            if (!empty($ori_ids)) {
                foreach ($ori_ids as $v) {
                    $this->clearRedisPermission(0, $v['id']);

                }
            }
            $count = $this->ddao->delete([], $componentIds);
            Db::commit();
            return ApiUtils::send(ErrorCode::SUCCESS, '删除成功', $count);
        } catch (\Throwable $e) {
            Db::rollBack();
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '删除失败' . config('web.err_msg_splite') . $e->getMessage());
        }

    }

    //递归找子类
    public function getSon($pids)
    {
        $componentIds = $this->cdao->searchAllId([], $pids);
        if (!empty($componentIds)) {
            $componentIds = array_merge($componentIds, $this->getSon($componentIds));
        }
        return $componentIds;
    }

    public function componentInfo($params)
    {
        $where[] = ['id', '=', $params['id']];
        $info = $this->cdao->searchFirst($where);
        if (empty($info)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '该功能不存在');
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $info->toArray());

    }

    public function moduleList($params)
    {
        //查找公司开启的模块
        $has = $this->companyMoudleId($params['login_usr']['company_id']);
        //找出已完成的模块
        $sub = $this->componentCate($params);
        $module = $sub['data'];
        foreach ($module as $k => $v) {
            $where = [];
            $where[] = ['module_id', '=', $v['id']];
            $data = $this->cdao->searchAll($where, [], ['component_name', 'content', 'icon', 'id', 'pid', 'url', 'module_id', 'sort', 'identity', 'is_web']);
            if (!empty($data)) {
                $module[$k]['son'] = FunctionUtil::getTree($data);
            }
            if (\in_array($data[0]['module_id'] ?? 0, $has)) {
                $module[$k]['is_open'] = 1;
            } else {
                $module[$k]['is_open'] = 2;
            }
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $module);
    }

    public function topModuleList($params)
    {
        //查找公司开启的模块
        $has = $this->companyMoudleId($params['login_usr']['company_id']);
        //找出已完成的模块
        $sub = $this->componentCate($params);
        $module = $sub['data'];
        foreach ($module as $k => $v) {
            $where = [];
            $where[] = ['module_id', '=', $v['id']];
            $where[] = ['pid', '=', 0];
            $data = $this->cdao->searchAll($where, [], ['component_name', 'content', 'icon', 'id', 'pid', 'url', 'module_id', 'sort', 'identity', 'is_web']);
            if (!empty($data)) {
                $module[$k]['son'] = $data;
            }
            if (\in_array($data[0]['module_id'] ?? 0, $has)) {
                $module[$k]['is_open'] = 1;
            } else {
                $module[$k]['is_open'] = 2;
            }
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $module);
    }

    public function EnableModule($params)
    {
        $where = [];
        $where[] = ['id', '=', $params['id']];
        //找出已完成的子模块
        $sub = $this->mdao->searchFirst($where);
        if (!empty($sub)) {
            $has = $this->companyMoudleId($params['login_usr']['company_id']);
            if (in_array($sub['id'], $has)) {
                throw new BusinessException(ErrorCode::ERR_BUESSUS, '模块已开启,请不要重复开启');
            }
            if ($sub['appkey'] == $params['appkey'] && $sub['url'] == $params['url']) {
                $tmp = [];
                $tmp['module_id'] = $params['id'];
                $tmp['company_id'] = $params['login_usr']['company_id'];
                $id = make(CompanyModuleDao::class)->add($tmp);
                make(AuthAdminLogDao::class)->addLog('开启了模块功能' . json_encode($params));
                return ApiUtils::send(ErrorCode::SUCCESS, '开启成功', $id);
            } else {
                throw new BusinessException(ErrorCode::ERR_BUESSUS, '地址或密匙不对');
            }
        } else {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '没有改模块');
        }

    }

    public function componentConfigList($params)
    {

        $data = $this->cdao->pageByWhere([], $params['pageSize']);
        $list = [];
        if (!empty($data['data'])) {
            foreach ($data['data'] as $k => $v) {
                $list[$k]['component_cata'] = $v['module']['module_name'];
                $list[$k]['icon'] = $v['icon'];
                $list[$k]['component_name'] = $v['component_name'];
                $list[$k]['content'] = $v['content'];
                $list[$k]['url'] = $v['url'];
                $list[$k]['add_time'] = $v['add_time'];
                $list[$k]['id'] = $v['id'];
                $list[$k]['cate_id'] = $v['module']['id'];
            }
        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $list, $data['total']);
    }

    public function companyModuleList($params)
    {
        ///找出已开启的子模块
        $moduleIds = $this->companyMoudleId($params['login_usr']['company_id']);
        if (empty($moduleIds)) {
            return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', []);
        }
        $sub = $this->mdao->searchAll([], $moduleIds, ['module_name', 'id']);
        foreach ($sub as $k => $v) {
            $where = [];
            $where[] = ['module_id', '=', $v['id']];
            $data = $this->cdao->searchAll($where, [], ['component_name', 'content', 'icon', 'id', 'pid', 'url', 'module_id', 'sort', 'identity', 'is_web']);
            if (!empty($data)) {
                $sub[$k]['son'] = FunctionUtil::getTree($data);
            } else {
                $sub[$k]['son'] = [];
            }

        }
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $sub);
    }

    //查找公司开启的模块id
    public function companyMoudleId($company_id)
    {
        $where = [];
        $where[] = ['company_id', '=', $company_id];
        return make(CompanyModuleDao::class)->searchMoudleId($where);
    }

    public function departAddComponent($params)
    {
        $component = \explode(',', $params['component_id']);
        $component = array_unique($component);
        //非组件不能添加
        $topIds = [];
        foreach ($component as $v) {
            $is = [];
            $is[] = ['id', '=', $v];
            $info = $this->cdao->searchFirst($is);
            if (empty($info)) {
                $topIds[] = $v;
            }
        }
        if (!empty($topIds)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, implode(',', $topIds) . '不是功能不能被添加');
        }
        Db::beginTransaction();
        try {
            //删除之前
            $where = [];
            $where[] = ['org_id', '=', $params['org_id']];
            $has = $this->ddao->delete($where);
            $map = [];
            foreach ($component as $k => $v) {
                if (empty($v)) {
                    continue;
                }
                $tmp = [];
                $tmp['component_id'] = $v;
                $tmp['org_id'] = $params['org_id'];
                $tmp['company_id'] = $params['login_usr']['company_id'];
                $map[] = $tmp;
            }
            $count = $this->ddao->insert($map);
            make(AuthOrganizationDao::class)->updateByIdTrait(['id' => $params['org_id'], 'cover_next' => $params['cover_next']]);
            make(AuthAdminLogDao::class)->addLog('部门添加了模块' . json_encode($params));
            $where5 = [];
            $where5[] = ['company_id', '=', $params['login_usr']['company_id']];
            $ori_ids = make(AuthOrganizationDao::class)->getByWhereTrait($where5, ['id'])->toArray();
            if (!empty($ori_ids)) {
                foreach ($ori_ids as $v) {
                    $this->clearRedisPermission(0, $v['id']);
                }
            }
            Db::commit();
            return ApiUtils::send(ErrorCode::SUCCESS, '添加成功', $count);

        } catch (\Throwable $e) {
            Db::rollBack();
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '添加部门权限失败' . config('web.err_msg_splite') . $e->getMessage());
        }
    }

    //部门已被分配的模块
    public function departHasComponent($params)
    {
        $where = [];
        $where[] = ['org_id', '=', $params['org_id']];
        $list = $this->ddao->searchComponentId($where);

        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', $list);

    }

    // //查找部门权限(树形结构)
    // public function searchDepartModule($moduleIds, $company_id)
    // {
    //     if (!empty($moduleIds)) {
    //         $where = [];
    //         $where[] = ['company_id', '=', $company_id];
    //         //找出栏目列表
    //         $list = $this->menudao->searchAll($where);
    //         foreach ($list as $k => $v) {
    //             $where1 = [];
    //             $where1[] = ['menu_id', '=', $v['id']];
    //             //找出每个栏目下自己的模块
    //             $module_ids = $this->mcdao->searchMoudleIdByModule($where1, $moduleIds);
    //             //找出模块的顶级id 因为部门权限没存顶级id
    //             // $where2 = [];
    //             // $where2[] = ['pid','=', 0];
    //             // $p_ids = $this->dao->searchAllId($where2);
    //             // $module_ids = array_merge($module_ids,$p_ids);
    //             if (empty($module_ids)) {
    //                 unset($list[$k]);
    //                 continue;
    //             }
    //             //把模块追加到栏目下
    //             $menu = $this->cdao->searchAll([['is_web', '=', 1]], $module_ids, ['component_name', 'content', 'icon', 'id', 'pid', 'url', 'module_id', 'identity']);
    //             $list[$k]['menu'] = FunctionUtil::getTree($menu);

    //             $module = $this->cdao->searchAll([], $module_ids, ['component_name', 'content', 'icon', 'id', 'pid', 'url', 'module_id', 'identity']);
    //             $list[$k]['module'] = FunctionUtil::getTree($module);
    //             unset($list[$k]['modules']);
    //         }
    //     } else {
    //         $list = [];
    //     }

    //     return array_values($list);
    // }

    //查找部门权限(树形结构)
    public function searchDepartModule($moduleIds, $company_id)
    {
        if (!empty($moduleIds)) {
            $where = [];
            $where[] = ['company_id', '=', $company_id];
            //找出栏目列表
            $list = $this->menudao->searchAll($where);
            if (!empty($list)) {
                foreach ($list as $k => $v) {
                    //找出这个菜单下的所有菜单
                    $allMenuIds = make(MenuService::class)->getSon([$v['id']]);
                    $allMenuIds[] = $v['id'];
                    //找出菜单下所有的组件
                    $allComponentIds = $this->mcdao->searchMoudleId([], $allMenuIds);
                    $newComponentIds = array_intersect($allComponentIds, $moduleIds);
                    //菜单下没有组件就删除
                    if (empty($newComponentIds)) {
                        unset($list[$k]);
                    } else {
                        $menuIds = [];
                        $menuIds = $this->mcdao->searchMoudleIdByModule([['menu_id', '=', $v['id']]], $moduleIds);
                        if (!empty($menuIds)) {
                            $list[$k]['component'] = $this->cdao->searchAll([['is_web', '=', Component::IS_WEB]], $menuIds, ['id', 'content', 'component_name', 'icon', 'url', 'sort', 'identity', 'is_web']);
                        }
                        unset($list[$k]['components']);
                    }

                }
            }
            $list = FunctionUtil::getTree($list);
            $identity = make(ComponentDao::class)->getByWhereInGroup($moduleIds);
            $data['identity'] = $identity;

            $data['menu'] = $list;

        } else {
            $data = [];
        }
        return $data;
    }

    /**
     * 获取当前用户员工部门权限模块
     *
     * @Author czm
     * @DateTime 2020-09-29
     * @param [type] $params
     * @return void
     */
    public function userHasModule($params)
    {
        $employee = make(AuthEmployeeDao::class)->findTrait($params['employee_id']);

        $org_id = $employee->organization_id;
        $componentIds = [];
        while ($org_id && empty($componentIds)) {
            $componentIds = $this->departHasComponent(['org_id' => $org_id])['data'] ?? [];
            //查找上级下发的权限模块
            $org_id = make(AuthOrganizationDao::class)->findTopCover($org_id);
        }
        //获取用户角色权限
        $component_id = make(AuthRoleComponentDao::class)->
            pluckByWhereTrait([['role_id', "=", $employee->role_id]], 'component_id')
            ->toArray();
        if (!empty($component_id)) {
            $componentIds = array_merge($componentIds, $component_id);
        }
        $permission = $this->searchDepartModule($componentIds, $employee->company_id);
        // var_dump($permission);
        $key_permission = config('web.permission_redis_key') . $employee->id;
        //跟token时间同步
        $this->redis->set($key_permission, Json::encode($permission), ['EX' => config('web.jwt_token_time')]);
        return ApiUtils::send(ErrorCode::SUCCESS, '获取成功', ['cache_key' => $key_permission, 'db' => env('REDIS_DB', 0)]);

    }

    /**
     * 清除权限redis缓存
     *
     * @Author czm
     * @DateTime 2020-12-03
     * @param integer $role_id
     * @param integer $organization_id
     * @param integer $employee_id
     * @return void
     */
    public function clearRedisPermission($role_id = 0, $organization_id = 0, $employee_id = 0)
    {
        $employee_ids = [];

        if ($role_id) {
            $ids = make(AuthEmployeeDao::class)->
                pluckByWhereTrait([['role_id', "=", $role_id]], 'id')
                ->toArray();
            $employee_ids = array_merge($employee_ids, $ids);
        }

        if ($organization_id) {
            $ids = make(AuthEmployeeDao::class)->
                pluckByWhereTrait([['organization_id', "=", $organization_id]], 'id')
                ->toArray();
            $employee_ids = array_merge($employee_ids, $ids);
        }

        if ($employee_id) {
            $employee_ids[] = $employee_id;
        }

        $rediskeys = [];
        foreach ($employee_ids as $val) {
            $rediskeys[] = config('web.permission_redis_key') . $val;
        }
        if ($rediskeys) {
            $this->redis->del($rediskeys);
        }
        return;
    }
}
